#!/bin/sh
######################################################################
#
# WANsim v1.5 by Ferry Hendrikx, (c) 2008-2009
#
# chkconfig: 2345 10 60
# description: WANsim provides an emulated WAN on your Linux server
######################################################################

### BEGIN INIT INFO
# Provides:             wansim
# Should-Start:
# Required-Start:       $local_fs $network
# Required-Stop:        $local_fs $network
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    Start and stop emulated WAN
# Description:          WANsim provides an emulated WAN on your Linux server
### END INIT INFO

PATH=/sbin:/bin


# configuration

CONF_BR="/var/lib/wansim/wansim.conf"
CONF_IF="/var/lib/wansim/interfaces.conf"
VERBOSE=no


# get lsb functions

if [ -e "/lib/init/vars.sh" ]; then
    . /lib/init/vars.sh
    . /lib/lsb/init-functions
fi


# utils

PROG_BR="/usr/sbin/brctl"
PROG_ET="/usr/sbin/ethtool"
PROG_IF="/sbin/ifconfig"
PROG_TC="/sbin/tc"
PROG_RT="/sbin/route"


# sanity check

if [ ! -e "${PROG_BR}" ]; then
    exit 3
fi

if [ ! -e "${PROG_IF}" ]; then
    exit 3
fi

if [ ! -e "${PROG_TC}" ]; then
    exit 3
fi

if [ ! -e "${PROG_RT}" ]; then
    exit 3
fi


# load configuration

if [ -e "${CONF_BR}" ]; then
    . ${CONF_BR}
else
    exit 3
fi


do_start () {
    [ $VERBOSE = "no" ] || log_action_begin_msg "Starting WANsim"


    # bring down interfaces

    $PROG_IF ${IFACE0} down
    $PROG_IF ${IFACE1} down


    # bring up interfaces

    $PROG_IF ${IFACE0} 0.0.0.0 mtu ${MTUSIZE} up
    $PROG_IF ${IFACE1} 0.0.0.0 mtu ${MTUSIZE} up


    # set interfaces

    if [ -e "${CONF_IF}" ]; then
        . ${CONF_IF}

        if [ -e "${PROG_ET}" ]; then
            $PROG_ET -s ${IFACE0} autoneg ${IF0AUTONEG}
            $PROG_ET -s ${IFACE0} speed ${IF0SPEED}
            $PROG_ET -s ${IFACE0} duplex ${IF0DUPLEX}

            $PROG_ET -s ${IFACE1} autoneg ${IF1AUTONEG}
            $PROG_ET -s ${IFACE1} speed ${IF1SPEED}
            $PROG_ET -s ${IFACE1} duplex ${IF1DUPLEX}
        fi
    fi


    # bring up bridge

    $PROG_BR addbr ${BRIDGE}
    $PROG_BR addif ${BRIDGE} ${IFACE0}
    $PROG_BR addif ${BRIDGE} ${IFACE1}
    $PROG_BR stp   ${BRIDGE} off

    if [ "$BRIDGEIP" != "0.0.0.0" ]; then
        # ensure the mask exists if not specified

        if [ -z "$BRIDGEMASK" ]; then
            BRIDGEMASK=255.255.255.0
        fi

        $PROG_IF ${BRIDGE} ${BRIDGEIP} netmask ${BRIDGEMASK}
        $PROG_RT add default gw ${BRIDGEGW}
    fi

    $PROG_IF ${BRIDGE} up


    # settings for iface0

    $PROG_TC qdisc add dev ${IFACE0} root handle 10:0 netem delay ${LATENCY}ms ${VARIATION}ms 75%
    $PROG_TC qdisc add dev ${IFACE0} parent 10:1 handle 11: tbf rate ${BANDWIDTH}kbit burst ${BURST} latency 100ms

    if [ "$PKTLOSS" -gt 0 -o "$PKTDUPL" -gt 0 -o "$PKTCORR" -gt 0 ]; then
        $PROG_TC qdisc add dev ${IFACE0} parent 11:1 handle 12: netem loss ${PKTLOSS}%
        $PROG_TC qdisc add dev ${IFACE0} parent 12:1 handle 13: netem duplicate ${PKTDUPL}%
        $PROG_TC qdisc add dev ${IFACE0} parent 13:1 handle 14: netem corrupt ${PKTCORR}%
    fi


    # settings for iface1

    $PROG_TC qdisc add dev ${IFACE1} root handle 20:0 netem delay ${LATENCY}ms ${VARIATION}ms 75%
    $PROG_TC qdisc add dev ${IFACE1} parent 20:1 handle 21: tbf rate ${BANDWIDTH}kbit burst ${BURST} latency 100ms

    if [ "$PKTLOSS" -gt 0 -o "$PKTDUPL" -gt 0 -o "$PKTCORR" -gt 0 ]; then
        $PROG_TC qdisc add dev ${IFACE1} parent 21:1 handle 22: netem loss ${PKTLOSS}%
        $PROG_TC qdisc add dev ${IFACE1} parent 22:1 handle 23: netem duplicate ${PKTDUPL}%
        $PROG_TC qdisc add dev ${IFACE1} parent 23:1 handle 24: netem corrupt ${PKTCORR}%
    fi


    # disable any filters

    if [ -d "/proc/sys/net/bridge" ]; then
        for FILT in /proc/sys/net/bridge/bridge-nf-*; do
            echo "0" > ${FILT}
        done
    fi

    [ $VERBOSE = "no" ] || log_action_end_msg 0
}

do_stop () {
    [ $VERBOSE = "no" ] || log_action_begin_msg "Stopping WANsim"

    $PROG_TC qdisc del dev ${IFACE0} root
    $PROG_TC qdisc del dev ${IFACE1} root

    $PROG_IF ${BRIDGE} down
    $PROG_BR delbr ${BRIDGE}

    [ $VERBOSE = "no" ] || log_action_end_msg 0
}


case "$1" in
    start|"")
        do_start
    ;;
    restart|reload|force-reload)
        do_stop
        do_start
    ;;
    stop)
        do_stop
    ;;
    *)
        echo "Usage: wansim [start|restart|reload|stop]" >&2
        exit 3
    ;;
esac

exit 0
